package cn.wolfcode.luowowo.service.impl;

import cn.wolfcode.luowowo.domain.Destination;
import cn.wolfcode.luowowo.domain.Strategy;
import cn.wolfcode.luowowo.domain.StrategyCatalog;
import cn.wolfcode.luowowo.query.StrategyCatalogQuery;
import cn.wolfcode.luowowo.repository.StrategyCatalogRepository;
import cn.wolfcode.luowowo.repository.StrategyRepository;
import cn.wolfcode.luowowo.service.IDestinationService;
import cn.wolfcode.luowowo.service.IRegionService;
import cn.wolfcode.luowowo.service.IStrategyCatalogService;
import cn.wolfcode.luowowo.util.AssertUtil;
import cn.wolfcode.luowowo.util.DBHelper;
import cn.wolfcode.luowowo.vo.CatalogVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.annotation.QueryAnnotation;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.redis.connection.RedisZSetCommands;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;

@Service
//@Transactional  暂时先别管事务
public class StrategyCatalogServiceImpl implements IStrategyCatalogService {
    
    @Autowired
    private StrategyCatalogRepository repository;
    
    @Autowired
    private MongoTemplate template;
    
    @Autowired
    private IDestinationService destinationService;
    @Autowired
    private StrategyServiceImpl strategyService;
    
    //查询单个方法
    public StrategyCatalog get(String id) {
        Optional<StrategyCatalog> optional = repository.findById(id);
        if (optional.isPresent()) {
            return optional.get();
        }
        return null;
    }
    
    //条件查询
    //page对象里面包括: 总页数 每页显示条数......
    public Page<StrategyCatalog> query(StrategyCatalogQuery qo) {
        /*创建一个空的条件*/
        Query query = new Query();
        
        /*模糊高查*/
        if (StringUtils.hasLength(qo.getKeyword())) {
            /*通过name模糊查询*/
            query.addCriteria(Criteria.where("name").regex(".*" + qo.getKeyword() + ".*"));
        }
        /*按照排序进行排序*/
        PageRequest sequence = PageRequest.of(qo.getCurrentPage() - 1, qo.getPageSize(), Sort.Direction.ASC, "sequence");
        /*工具类传进条件后 进行数据的排序与分页*/
        return DBHelper.query(template, StrategyCatalog.class, query, sequence);
        
    }
    
    /*查询全部的内容*/
    public List<StrategyCatalog> list() {
        return repository.findAll();
    }
    
    
    /**
     * 删除方法
     *
     * @param id 删除的id
     */
    @Override
    public void delete(String id) {
        repository.deleteById(id);
    }
    
    /**
     * 编辑与添加的方法
     *
     * @param strategyCatalog
     */
    @Override
    public void saveOrUpdate(StrategyCatalog strategyCatalog) {
        /*判空操作*/
        AssertUtil.hasLength(strategyCatalog.getName(), "请输入攻略分类的名称!");
        AssertUtil.intNotNull(strategyCatalog.getSequence(), "请输入分类的排序!");
        /*修改与添加都需要将目的地的id转换成name*/
        /*修改id为name*/
        strategyCatalog.setDestName(destinationService.get(strategyCatalog.getDestId()).getName());
        repository.save(strategyCatalog);
    }
    
    /**
     * 查询分类及下面的主题进行封装
     *
     * @return
     */
    @Override
    public List<CatalogVO> getCatalogs() {
        //创建空的catalogvo的集合 后面用于封装 接收的是catalogvo这个对象 的集合
        ArrayList<CatalogVO> catalog = new ArrayList<>();
        //进行数据的查询 得到一条数据的文档
        /*参数解析
        * StrategyCatalog.class             说明进行聚合的是哪张表 因为真实类中有个标签是表明了使用的表的
        * Aggregation.group("destName")     说明的是表中进行第一过滤的是哪个数据,并且对起进行去重
        * push("name").as("names")          说明增加一个数组类型的数据,里面放的是根据destName获取的name字段的值集合
        * .push("id").as("ids")             说明与上与上面的一样,也是添加一个list集合
        * */
        TypedAggregation<StrategyCatalog> agg = Aggregation.newAggregation(StrategyCatalog.class,
                Aggregation.group("destName")
                        .push("id").as("ids")
                        .push("name").as("names")
        );
        //进行循环封装
        //将上面获取的值进行封装,上面查询得值就是可以封装一个map中,就是一个文档一个map,map里面是可以获取不不止一个键对值得
        //例如键对值 {_id:destName ,names:xx,ids:xxx}
        //这个是获取多个的 所以里面的结果可以list取出
        AggregationResults<Map> aggregate = template.aggregate(agg, Map.class);
        //获取上面的文档将其用集合的方式取出
        List<Map> results = aggregate.getMappedResults();
        for (Map data:results) {
            CatalogVO catalogVO = new CatalogVO();
            /*封装key 为destName*/
            catalogVO.setDestName(data.get("_id").toString());
            //一个空的集合map 用于封装list<map>里面的names与ids
            ArrayList<Map<String,Object>> mapList = new ArrayList<>();
            //将data中的names元素全部取出用list的方式封装
            List<Object> names = (List<Object>) data.get("names");
            //将data中的ids元素全部取出用list的方式封装
            List<Object> ids = (List<Object>) data.get("ids");
            //将取出的值用空的map进行封装 但是需要先循环,因为是list集合
            for (int i = 0 ; i < names.size();i++){
                //创建一个空的map用来装kv值
                HashMap<String, Object> map = new HashMap<>();
                //取出循环的值
                String name = names.get(i).toString();
                String id = ids.get(i).toString();
                //然后装进map中
                map.put("id",id);
                map.put("name",name);
                //然后将这个map放进空的集合中 在循环里面添加
                mapList.add(map);
            }
            //将list的值加到vo里面
            catalogVO.setMapList(mapList);
            //最后将这个对象装进catalog的集合 中
            catalog.add(catalogVO);
        }
        //返回大集合
        return catalog;
    }
    //查询分类及攻略明细
    @Override
    public List<StrategyCatalog> selectCatalogByDestId(String destId) {
        //查询目的地下所有的分类
        List<StrategyCatalog> catalog = repository.findByDestId(destId);
        //查询分类下的攻略明细 因为domain里面是放着攻略明细的空集合 所有根据分类对象集合来查询出数据后封装进集合就行
        for (StrategyCatalog sts : catalog) {
            List<Strategy> strategies = strategyService.selectTitleByCataId(sts.getId());
            //将获取的值set到domain的真实类里面的集合中
            sts.setStrategies(strategies);
        }
        return catalog;
    }
    
}
